#ifndef OPENSIM_PROPERTY_H_
#define OPENSIM_PROPERTY_H_
/* -------------------------------------------------------------------------- *
 *                            OpenSim:  Property.h                            *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2017 Stanford University and the Authors                *
 * Author(s): Michael A. Sherman                                              *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
 * not use this file except in compliance with the License. You may obtain a  *
 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 * -------------------------------------------------------------------------- */

// INCLUDES
#include "AbstractProperty.h"
#include "Exception.h"

#include "SimTKcommon/SmallMatrix.h"
#include "SimTKcommon/internal/BigMatrix.h"
#include "SimTKcommon/internal/Transform.h"
#include "SimTKcommon/internal/Array.h"
#include "SimTKcommon/internal/ClonePtr.h"

#include <iomanip>

namespace OpenSim {

template <class T> class SimpleProperty;
template <class T> class ObjectProperty;

//==============================================================================
//                                PROPERTY
//==============================================================================

/** A %Property\<T> is a serializable (name, list-of-values) pair, where each 
value is of type T. The number of values allowed in the list is an attribute of
the property; often it is just a single value. Properties are owned by classes
that derive from %OpenSim's serializable Object base class. The documentation 
here is most useful for developers who are interested in creating a new 
Component, ModelComponent, or other serializable class derived from Object.

A property's contained type T must be a serializable type. Serializable types 
come in two flavors:
  - simple types (like int or string) for which serialization instructions 
    have been provided, and
  - object types, in which case type T derives from Object and knows
    how to serialize itself.

When T is a simple type we'll write T=S and refer to a %Property\<S> as a 
"simple property". When T is an object type, we'll write T=O and
refer to a %Property\<O> as an "object property".

In case type O is a still-abstract Object-derived type like Function or 
Controller, a %Property\<O> can hold a mix of any concrete objects derived from 
O (e.g., any Object that can be dynamic_cast to a Function can be
held by a %Property\<Function>).

The objects in an object property will themselves have
properties so a %Property\<O> can be viewed as a node in the tree of objects
that constitute an %OpenSim Model. Simple properties %Property\<S> can be 
viewed as the terminal nodes of that tree. Properties are thus an integral part
of the structure of an %OpenSim Model; anything contained in a property is 
owned by that property; deleting the property deletes its contained objects. If
you want to \e reference another Object from within a property, use a string 
property to reference it by name; the result is a simple property. It is not
permitted for type T to be a pointer or reference.

<h3>XML file representation of properties</h3>

The general representation for a %Property\<T> with name "prop_name" is
@code
    <prop_name> T T ... T </prop_name>
@endcode
where "T" is the XML representation for objects of type T. Note that if T is
an object type O, its representation follows the pattern
@code
    <OTypeName> OContents </OTypeName>
@endcode
where \c OTypeName stands for the name of the concrete, Object-derived class
being serialized, and \c OContents is the representation generated by that
class when asked to serialize itself.

A %Property\<O> that is restricted to holding <em>exactly one</em> object of 
type O is called a "one-object property". It could be represented in XML as
@code
    <prop_name> <OTypeName> OContents </OTypeName> </prop_name>
@endcode
but we allow a more compact representation for one-object properties:
@code
    <OTypeName name="prop_name"> OContents </OTypeName>
@endcode
In the one-object case it is also permissible for the property to be unnamed, 
in which case it may be referenced as though its name were the same as the 
object type name, and there is no separate "name" attribute. The XML 
representation for an unnamed property is just:
@code
    <OTypeName> OContents </OTypeName>
@endcode
On input, if a name attribute is seen for an unnamed property it is ignored; 
only the object type name tag matters in the unnamed case. Note that only 
one-object properties can be unnamed, and no single %OpenSim object can have 
more than one unnamed property of the same type.

<h3>%Property attributes</h3>

In addition to the name and list of values, every property has the following
attributes:
  - A comment string, provided at the time the property is created.
  - The minimum and maximum number of values allowed.
  - A "used default value" flag.

The "used default value" flag specifies that the value stored with this 
property was taken from a default object and not subsequently changed. A 
property with this flag set is not written out when a model is serialized. 

<h3>How to declare properties in your class declaration</h3>

Properties are maintained in a PropertyTable by %OpenSim's Object base class 
that is used for all serializable objects. Do not create %Property objects 
directly; instead, use the provided macros to declare them in the class
declarations for objects derived from Object. These macros should appear in the 
header file near the top of your class declaration. Comments that should appear
in the generated Doxygen documentation as well as in XML files should be in the
comment string; if you have a comment that should appear in Doxygen
documentation but not in XML, then you can place it in a Doxygen comment just
above the line where you declare your property.

<b>Naming conventions:</b> %OpenSim property names should use lower case letters
with \c words_separated_by_underscores. In contrast, %OpenSim object types 
begin with a capital letter and use camel case, that is, 
\c MixedUpperAndLowerLikeThis. This prevents any possible collisions between 
property names and object types, allowing both to be used as XML tag
identifiers with no conflicts.

These are the most common forms of property declaration.  Click on the macro
names below for more information.
@code
    // Exactly one value required; this is the basic property type.
    OpenSim_DECLARE_PROPERTY(name, T, "property description");
    // Zero or one value only.
    OpenSim_DECLARE_OPTIONAL_PROPERTY(name, T, "property description");
    // Zero or more values.
    OpenSim_DECLARE_LIST_PROPERTY(name, T, "property description");
@endcode
In the above, T may be a simple type S or object type O. In the case of a 
single-value property where type T is a type derived from
Object (i.e., T=O), you can declare the property to be unnamed and instead use 
the class name of the object type O to identify the property:
@code
    // Exactly one value of object type O required.
    OpenSim_DECLARE_UNNAMED_PROPERTY(O, "property description");
@endcode
Only one unnamed property of a particular object type O may be declared in
any given Object.

Finally, for list properties you can declare restrictions on the allowable
list length:
@code
    // List must contain exactly listSize (> 0) elements.
    OpenSim_DECLARE_LIST_PROPERTY_SIZE(name, T, listSize, 
                                       "property description");
    // List must contain at least minSize (> 0) elements.
    OpenSim_DECLARE_LIST_PROPERTY_ATLEAST(name, T, minSize, 
                                          "property description");
    // List must contain at most maxSize (> 0) elements.
    OpenSim_DECLARE_LIST_PROPERTY_ATMOST(name, T, maxSize, 
                                         "property description");
    // List must contain between minSize (> 0) and maxSize (>minSize) elements.
    OpenSim_DECLARE_LIST_PROPERTY_RANGE(name, T, minSize, maxSize, 
                                        "property description");
@endcode
Here is an example of an object declaring two properties: **/
///@code
///  class ActuatorWorkMeter : public ModelComponent {
///  OpenSim_DECLARE_CONCRETE_OBJECT(ActuatorWorkMeter, ModelComponent);
///  public:
///  //=======================================================================
///  // PROPERTIES
///  //=======================================================================
///      OpenSim_DECLARE_PROPERTY(actuator_name, std::string,
///          "The name of the actuator whose work use will be calculated.");
///      /** The value for this property is used for reporting purposes. */
///      OpenSim_DECLARE_PROPERTY(initial_actuator_work, double,
///          "Initial value for work; normally zero.");
///  //=======================================================================
///  // PUBLIC METHODS
///  //=======================================================================
///      ...
///  };
///@endcode
/**
<h3>How to construct properties in your constructors</h3>

The constructors for your Object-derived class are required to construct and
initialize the properties to whatever default values you want them to have.
The above macros will have generated for each property a method for this
purpose. If your property is named <em>prop_name</em>, then the method will be 
called constructProperty_<em>prop_name</em>(). (In the case of unnamed 
properties, the object type serves as <em>prop_name</em>.) The initial value is 
provided as an argument, which is optional for those properties that are 
allowed to contain a zero-length value list. Here are the various types of 
generated construction methods:
@code
    // Construct and initialize a single-valued property containing type T.
    void constructProperty_prop_name(const T& value);
    // Construct a property with a zero-length value list. 
    void constructProperty_prop_name();
    // Construct a list property, initializing from a container.
    template <template <class> class Container>
    void constructProperty_prop_name(const Container<T>& valueList);
@endcode
The first form above is generated for basic, optional, and unnamed properties.
The second, uninitialized form is generated for optional, unrestricted list,
and list "atmost" properties, since those can accept a zero-element value list.
The last form is generated for all list properties, regardless of size
restriction; a runtime check verifies that size restrictions are met. That 
form accepts any container type that supports a %size() method and random access
element selection with operator[], such as std::vector<T>, 
OpenSim::Array<T>, or SimTK::Array_<T>.

The above methods are conventionally collected into a private method of each
object class called \c constructProperties(). This method is then invoked from
every constructor, \e except the copy constructor (which you normally should
let the compiler generate, but see below).

<h4>Copy constructor and copy assignment operator</h4>

Your best bet is to use the compiler-generated default copy constructor and
default copy assignment operator that you get whenever you leave these methods
undefined. If you do that, all your properties and their associated local
data will be copied automatically. It is worth some effort to design your
objects so that their data members can copy and assign themselves correctly;
you might find SimTK::ReferencePtr<T> and SimTK::ClonePtr<T> useful for getting
pointer members to behave themselves properly.

However, if you do have to write your own copy constructor and copy assignment
operator (and if you write one you must write the other also), the 
property table will still have been copied properly by your superclass, it is 
only the local property indices that you have to deal with. For that, each 
property has defined a method like:
@code
    // Copy the local data member associated with property prop_name.
    void copyProperty_prop_name(const Self& source);
@endcode
In the above, \c Self is the type of the object being defined and \c source is
the argument that was passed to the containing copy constructor or copy 
assignment operator.

<h3>Runtime access to property values</h3>

The property declaration macros also generate per-property methods for getting
access to property values or the %Property objects themselves. These inline
methods are very fast and can be used whenever you need access to a property 
value. The following are generated for single-valued property types, including
the basic, optional, and unnamed properties:
@code
    // Get a const reference to the value of a single-valued property 
    // named "prop_name" (basic, optional, unnamed properties only).
    const T& get_prop_name() const;
    // Same, but returns a writable reference.
    T& upd_prop_name();
    // Set the value of a single-valued property.
    void set_prop_name(const T& value);
@endcode

Additional methods are generated for list properties:
@code
    // Get a const reference to the i'th element in a list property's value 
    // list.
    const T& get_prop_name(int i) const;
    // Same, but returns a writable reference.
    T& upd_prop_name(int i);
    // Set the i'th element of a list property to the given value. Only 
    // allowed if the list currently has at least i elements, so no gaps can
    // be created with this method.
    void set_prop_name(int i, const T& value);
    // Use this to append one element to a list property's value list; the
    // assigned index is returned.
    int append_prop_name(const T& value);
    // Use this to set all the values of a list-valued property.
    template <template <class> class Container>
    void set_prop_name(const Container<T>& valueList);
@endcode
The last form accepts any container that has a %size() method and allows
element access using operator[]. Runtime checks verify that the list length
is within the allowable range for the property. Note that every property is 
considered to have a value list (even when restricted to one element) so the 
indexed forms above can also be used with single-valued properties as long as
the index is zero.

To get access to the %Property object rather than one of its values, the
following methods are provided:
@code
    // Get a const reference to the Property<T> object for "prop_name".
    const Property<T>& getProperty_prop_name() const;
    // Same, but returns a writable reference.
    Property<T>& updProperty_prop_name();
@endcode

The %Property\<T> class acts as a container of values, and has the usual 
%size(), %empty(), and operator[] methods available so you can use 
getProperty...() above to get access to those methods. For example, to write 
out all the values of any property:
@code
    // Assumes type T can be written to a stream with operator<<.
    for (int i=0; i < getProperty_prop_name().size(); ++i)
        std::cout << get_prop_name(i) << std::endl;
@endcode


@see OpenSim::Object, OpenSim::AbstractProperty 
@author Michael Sherman
**/
template <class T>
class Property : public AbstractProperty {
public:
    /** Provides type-specific methods used to implement generic functionality.
    This class must be specialized for any 
    type T that is used in a Property\<T> instantiation, unless T is an 
    Object or something derived from Object. **/
    struct TypeHelper;

    /** Make a new, deep copy (clone) of this concrete property and return
    a pointer to the heap space. Caller must delete the returned object when
    done with it. **/
    Property* clone() const override = 0;

    /** Use TypeHelper's getTypeName() to satisfy this pure virtual. **/
    // See below for implementation.
    std::string getTypeName() const override final;

    /** Get a const reference to one of the values in the value list. This will
    throw an exception if the index does not refer to an already-existing
    value. This operator is synonymous with getValue(i). **/
    const T& operator[](int i) const {return getValue(i);}
    /** Get a writable reference to one of the values in the value list. This 
    will throw an exception if the index does not refer to an already-existing
    value. This operator is synonymous with updValue(i). **/
    T& operator[](int i) {return updValue(i);}

    /** Assignment to a value of type T sets the value of this single-valued
    property to a copy of the supplied \a value; not allowed for a list 
    property. This does not invoke the assignment operator on the existing
    value. Instead, the value list is cleared and then replaced by the new 
    value. This is synonymous with setValue(value). **/
    Property& operator=(const T& value) {
        setValue(value);
        return *this;
    }

    /** Assignment to a container of values of type T sets the entire value
    list of this list property to a copy of the values in the container. The
    current value list is cleared before the assignment. This is synonymous 
    with setValue(valueList). **/
    template< template <class> class Container >
    Property& operator=(const Container<T>& valueList) {
        setValue(valueList);
        return *this;
    }

    /** Replace the i'th value list element with a copy of the given \a value.
    The index i must be between 0 and the current list length, meaning it is
    OK to refer one element past the last element. In that case the new 
    \a value is appended to the list using appendValue(), which will throw an
    exception if the list is already at its maximum allowable size. In the case
    where index i refers to an existing element, a simple property 
    will assign a new value to the existing element but an object property 
    will delete the old object and replace it with a clone() of the new one 
    -- it will \e not invoke the old object's assignment operator. That means
    that the concrete object type may be changed by this operation, provided
    it is still a type derived from object type T. If you want to invoke the 
    existing value's assignment operator, use updValue(i) rather than 
    setValue(i). **/
    void setValue(int i, const T& value) {
        const int n = getNumValues();
        if (0 <= i && i <= n) {
            if (i==n) appendValue(value); // might fail
            else setValueVirtual(i, value);
            setValueIsDefault(false);
            return;
        }
        throw OpenSim::Exception(
            "Property<T>::setValue(i,value): index " + SimTK::String(i)
            + " out of range for property " + getName() 
            + " which currently has " + SimTK::String(n) + " values.");
    }

    /** Provide a new value for a single-valued
    property. The current value (if any) is replaced, and %size()==1 
    afterwards. An exception is thrown if this is a list property. **/
    void setValue(const T& value) {
        if (isListProperty()) {
            throw OpenSim::Exception(
                "Property<T>::setValue(value): property " + getName()
                + " is a list property so must be set either to a list "
                  "of values, or elementwise using indexing.");
        }
        setValue(0, value);
    }


    /** Assignment to a container of values of type T sets the entire value
    list of this list property to a copy of the values in the container. The
    current value is cleared before the assignment. **/
    template< template <class> class Container >
    void setValue(const Container<T>& valueList) {
        if (   valueList.size() < getMinListSize()
            || valueList.size() > getMaxListSize()) 
        {
            const std::string reqLen = getMinListSize()==getMaxListSize() 
                ? "exactly " + SimTK::String(getMinListSize())
                : "between " + SimTK::String(getMinListSize()) + 
                  " and " + SimTK::String(getMaxListSize());
                  
            throw OpenSim::Exception
               ("Property<T>::setValue(Container<T>): the number of elements "
                "supplied (" + SimTK::String(valueList.size()) + 
                ") was out of range " " for property " + getName() + 
                " which requires " + reqLen + " elements.");
        }
        clear();
        for (int i=0; i < valueList.size(); ++i)
            appendValueVirtual(valueList[i]);
        setValueIsDefault(false);
    }

    /** Return a const reference to the selected value from this property's 
    value list. If the property is at most single valued then the \a index is 
    optional and we'll behave as though index=0 were supplied. You can use
    the square bracket operator property[index] instead. **/
    const T& getValue(int index=-1) const {
        if (index < 0) {
            if (getMaxListSize()==1) index = 0;
            else throw OpenSim::Exception(
                "Property<T>::getValue(): an index must be "
                "provided for a property that takes a list "
                "of values.");
        }
        return getValueVirtual(index);
    }

    /** Return a writable reference to the selected value from this property's 
    value list. If the property is at most single valued then the \a index is 
    optional and we'll behave as though index=0 were supplied.  You can use
    the square bracket operator property[index] instead. **/
    T& updValue(int index=-1) {
        if (index < 0) {
            if (getMaxListSize()==1) index = 0;
            else throw OpenSim::Exception(
                "Property::updValue(): an index must be "
                "provided for a property that takes a list "
                "of values.");
        }
        setValueIsDefault(false);
        return updValueVirtual(index); 
    }

    /** Append a copy of the supplied \a value to the end of this property's 
    value list. An exception is thrown if the property can't hold any more 
    values. The index assigned to this value is returned. **/
    int appendValue(const T& value) {
        if (getNumValues() >= getMaxListSize())
            throw OpenSim::Exception(
                "Property::appendValue(T&): property " + getName() 
                + " can't hold any more than " 
                + SimTK::String(getMaxListSize()) + " values.");
        setValueIsDefault(false);
        return appendValueVirtual(value);
    }

    /** Append a \e copy of the supplied \a value to the end of this 
    property's value list. An exception is thrown if the property can't hold 
    any more values. The index assigned to this value is returned. Note that 
    although we  accept a pointer here, we do not take over ownership. See 
    adoptAndAppendValue() if you want the property to take ownership. **/
    int appendValue(const T* value) {
        if (value == NULL)
            throw OpenSim::Exception(
                "Property::appendValue(T*): null value not allowed.",
                __FILE__, __LINE__);
        if (getNumValues() >= getMaxListSize())
            throw OpenSim::Exception(
                "Property::appendValue(T*): property " + getName() 
                + " can't hold any more than "
                + SimTK::String(getMaxListSize()) + " values.");
        setValueIsDefault(false);
        return appendValueVirtual(*value);
    }

    /** Add a new value to the end of this property's value list, taking over
    ownership of the supplied heap-allocated object. An exception
    is thrown if the property can't hold any more values. The index assigned
    to this value is returned. **/
    int adoptAndAppendValue(T* value) {
        if (value == NULL)
            throw OpenSim::Exception(
                "Property::adoptAndAppendValue(T*): null value not allowed.");
        if (getNumValues() >= getMaxListSize())
            throw OpenSim::Exception(
                "Property::adoptAndAppendValue(T*): property " + getName() 
                + " can't hold any more than " + SimTK::String(getMaxListSize())
                + " values.");
        setValueIsDefault(false);
        return adoptAndAppendValueVirtual(value);
    }

    /** Search the value list for an element that has the given \a value and
    return its index if found, otherwise -1. This requires only that the 
    template type T supports operator==(). This is a linear search so will 
    take time proportional to the length of the value list. **/
    int findIndex(const T& value) const {
        const int nValues = getNumValues();
        for (int i=0; i < nValues; ++i)
            if (getValue(i) == value)
                return i;
        return -1;
    }

    /** Return index of passed in name if the Property contains objects that are
    derived from OpenSim::Object, and -1 if no such Object is found. Throws an 
    Exception if the List doesn't contain OpenSim Objects (e.g. primitive types)
    since these are not named. When a search is performed, it's a linear search. 
    **/
    virtual int findIndexForName(const SimTK::String& name) const = 0;

    /** Return true if the given AbstractProperty references a concrete
    property of this type (%Property\<T>). Note that for this to return true,
    the type T must be exactly the type used when the concrete property was
    allocated; it is not sufficient for T to be a more general base type from
    which the actual type was derived. **/
    static bool isA(const AbstractProperty& prop) 
    {   return dynamic_cast<const Property*>(&prop) != NULL; }

    /** Downcast the given AbstractProperty to a concrete
    property of this type (%Property\<T>). An exception is thrown if
    this is not the right type only in DEBUG mode; see isA() if you need to 
    check first. **/
    static const Property& getAs(const AbstractProperty& prop) {
        const Property* p = SimTK_DYNAMIC_CAST_DEBUG<const Property*>(&prop);
        if (p) return *p;
        throw OpenSim::Exception
           ("Property<T>::getAs(): Property " + prop.getName() 
            + " was not of type "
            + std::string(SimTK::NiceTypeName<T>::name()));
    }

    /** Downcast the given AbstractProperty to a writable concrete
    property of this type (%Property\<T>). An exception is thrown if
    this is not the right type only in DEBUG mode; see isA() if you need to 
    check first. **/
    static Property& updAs(AbstractProperty& prop) {
        Property* p = SimTK_DYNAMIC_CAST_DEBUG<Property*>(&prop);
        if (p) return *p;
        throw OpenSim::Exception
           ("Property<T>::updAs(): Property " + prop.getName() 
            + " was not of type "
            + std::string(SimTK::NiceTypeName<T>::name()));
    }

protected:
    Property() = default;
    ~Property() = default;
    Property(const Property&) = default;
    Property(Property&&) = default;
    Property& operator=(const Property&) = default;
    Property& operator=(Property&&) = default;
    /** @cond **/ // Hide from Doxygen.
    // This is the interface that SimpleProperty and ObjectProperty must
    // implement.
    // Base class verifies that 0 <= index < size(), and for append operations
    // that the list is permitted to grow.
    virtual const T& getValueVirtual(int index) const = 0;
    virtual T& updValueVirtual(int index) = 0;
    virtual void setValueVirtual(int index, const T& value) = 0;
    virtual int appendValueVirtual(const T& value) = 0;
    virtual int adoptAndAppendValueVirtual(T* value) = 0;
    /** @endcond **/
};


//==============================================================================
//                        TYPE HELPER SPECIALIZATIONS
//==============================================================================
// Declarations are here so they can be used in declarations of SimpleProperty
// and ObjectProperty but some definitions must be delayed until after
// SimpleProperty and ObjectProperty are declared.

/** This is the generic definition of Property::TypeHelper to be used 
whenever T does not have a specialization, meaning that T must be a type 
derived from class Object. Any non-Object type that is to be used as a property 
type \e must provide a specialization of this class. **/
template <class T> struct Property<T>::TypeHelper {
    static const bool IsObjectType = true;
    static ObjectProperty<T>* create(const std::string& name, bool isOne);
    static const std::string& getTypeName() {return T::getClassName();}
    static bool isEqual(const T& a, const T& b) {return a==b;}
};

#ifndef SWIG
/** TypeHelper specialization for bool. **/
template<> struct Property<bool>::TypeHelper {
    static const bool IsObjectType = false;
    static SimpleProperty<bool>* create(const std::string& name, bool isOne);
    static std::string getTypeName() {return "bool";}
    static bool isEqual(bool a, bool b) {return a==b;}
};
/** TypeHelper specialization for int. **/
template<> struct Property<int>::TypeHelper {
    static const bool IsObjectType = false;
    static SimpleProperty<int>* create(const std::string& name, bool isOne);
    static std::string getTypeName() {return "int";}
    static bool isEqual(int a, int b) {return a==b;}
};
/** TypeHelper specialization for std::string. **/
template<> struct Property<std::string>::TypeHelper {
    static const bool IsObjectType = false;
    static SimpleProperty<std::string>* 
        create(const std::string& name, bool isOne);
    static std::string getTypeName() {return "string";}
    static bool isEqual(const std::string& a, const std::string& b)
    {   return a==b; }
};

/** TypeHelper specialization for double. Note that isEqual() operator here
returns true if values are equal to within a tolerance. We also say NaN==NaN, 
which is not standard IEEE floating point behavior. **/
template<> struct Property<double>::TypeHelper {
    static const bool IsObjectType = false;
    static SimpleProperty<double>* create(const std::string& name, bool isOne);
    static std::string getTypeName() {return "double";}
    OSIMCOMMON_API static bool isEqual(double a, double b);
};
/** TypeHelper specialization for SimTK::Vec3; see double specialization
for information on floating point comparison. **/
template<> struct Property<SimTK::Vec3>::TypeHelper  {
    static const bool IsObjectType = false;
    static SimpleProperty<SimTK::Vec3>* 
        create(const std::string& name, bool isOne);
    static std::string getTypeName() {return "Vec3";}
    OSIMCOMMON_API static bool isEqual(const SimTK::Vec3& a, 
                                       const SimTK::Vec3& b);
};
/** TypeHelper specialization for SimTK::Vec6; see double specialization
for information on floating point comparison. **/
template<> struct Property<SimTK::Vec6>::TypeHelper  {
    static const bool IsObjectType = false;
    static SimpleProperty<SimTK::Vec6>*
        create(const std::string& name, bool isOne);
    static std::string getTypeName() { return "Vec6"; }
    OSIMCOMMON_API static bool isEqual(const SimTK::Vec6& a,
        const SimTK::Vec6& b);
};
/** TypeHelper specialization for SimTK::Vector; see double specialization
for information on floating point comparison. **/
template<> struct Property<SimTK::Vector>::TypeHelper  {
    static const bool IsObjectType = false;
    static SimpleProperty<SimTK::Vector>* 
        create(const std::string& name, bool isOne);
    static std::string getTypeName() {return "Vector";}
    OSIMCOMMON_API static bool isEqual(const SimTK::Vector& a, 
                                       const SimTK::Vector& b);
};

/** TypeHelper specialization for SimTK::Transform; see double specialization
for information on floating point comparison. **/
template<> struct Property<SimTK::Transform>::TypeHelper  {
    static const bool IsObjectType = false;
    static SimpleProperty<SimTK::Transform>* 
        create(const std::string& name, bool isOne);
    static std::string getTypeName() {return "Transform";}
    OSIMCOMMON_API static bool isEqual(const SimTK::Transform& a, 
                                       const SimTK::Transform& b);
};
#endif

//==============================================================================
//                    PROPERTY<T> INLINE IMPLEMENTATION
//==============================================================================
template <class T> inline std::string
Property<T>::getTypeName() const {
    return TypeHelper::getTypeName();
}

// Hide SimpleProperty and ObjectProperty from Doxygen; users don't need
// to know about these.
/** @cond **/

//==============================================================================
//                  HELPERS FOR WRITING PROPERTY VALUES 
//==============================================================================
// This section is hidden from SWIG because of compiling issues (i.e., SWIG
// thought these functions were part of Property in some cases, rather than
// free functions)
#ifndef SWIG

/** Take the `transform` argument, convert to a Vec6, and then append
the Vec6 to the end of the `rotTrans` Array. **/
inline void convertTransformToVec6(SimTK::Array_<SimTK::Vec6>& rotTrans,
    const SimTK::Transform& transform)
{
    SimTK::Vec6 X6;
    SimTK::Vec3& angles = X6.updSubVec<3>(0);
    SimTK::Vec3& pos = X6.updSubVec<3>(3);
    angles = transform.R().convertRotationToBodyFixedXYZ();
    pos = transform.p();
    rotTrans.push_back(X6);
}

template <class T> inline void
writeSimplePropertyToStreamForDisplay(std::ostream& o,
    T& v, const int precision)
{
    SimTK::writeUnformatted(o, v);
}

inline void
writeSimplePropertyToStreamForDisplay(std::ostream& o,
    const double v, const int precision)
{
    o << std::setprecision(precision);
    o << v;
}

template <int M> inline void
writeSimplePropertyToStreamForDisplay(std::ostream& o,
    const SimTK::Vec<M>& v, const int precision)
{
    o << std::setprecision(precision);

    o << "(";
    for (int i = 0; i < M; ++i) {
        if (i != 0) o << " ";
        o << v[i];
    }
    o << ")";
}

inline void
writeSimplePropertyToStreamForDisplay(std::ostream& o,
    const SimTK::Vector& v, const int precision)
{
    o << std::setprecision(precision);

    o << "(";
    for (int i = 0; i < v.size(); ++i) {
        if (i != 0) o << " ";
        o << v[i];
    }
    o << ")";
}

inline void
writeSimplePropertyToStreamForDisplay(std::ostream& o,
    const SimTK::Transform& v, const int precision)
{
    // Convert array of Transform objects to an array of Vec6 objects.
    SimTK::Array_<SimTK::Vec6> rotTrans;
    convertTransformToVec6(rotTrans, v);
    SimTK::Vec6 rotTransVec = rotTrans[0];

    o << std::setprecision(precision);

    o << "(";
    for (int i = 0; i < 6; ++i) {
        if (i != 0) o << " ";
        o << rotTransVec[i];
    }
    o << ")";
}

template <class T, class X> inline void
writeSimplePropertyToStreamForDisplay(std::ostream& o,
    const SimTK::Array_<T, X>& v, const int precision)
{
    OPENSIM_THROW_IF(precision <= 0, Exception,
        "precision argument must be greater than 0.");

    for (X i(0); i < v.size(); ++i) {
        if (i != 0) o << " ";
        writeSimplePropertyToStreamForDisplay(o, v[i], precision);
    }
}
#endif // SWIG

//==============================================================================
//                             SIMPLE PROPERTY
//==============================================================================
/** This subclass of Property<T> is used when type T=S is a "simple" type, 
meaning it is not derived from Object. **/
template <class T>
class SimpleProperty : public Property<T> {
public:
    /** A simple property must have a non-null name. **/
    SimpleProperty(const std::string& name, bool isOneValue) { 
        if (name.empty())
            throw OpenSim::Exception(
                "addProperty<" + std::string(SimTK::NiceTypeName<T>::name())
                + ">(): a simple (non-Object) property must have a name.");        
        this->setName(name); 
        if (isOneValue) this->setAllowableListSize(1); 
    }

    // Default destructor, copy constructor, copy assignment.

    SimpleProperty* clone() const override final 
    {   return new SimpleProperty(*this); }

    void assign(const AbstractProperty& that) override {
        try {
            *this = dynamic_cast<const SimpleProperty&>(that);
        } catch(const std::bad_cast&) {
            OPENSIM_THROW(InvalidArgument,
                          "Unsupported type. Expected: " + this->getTypeName() +
                          " | Received: " + that.getTypeName());
        }
    }
    
    // Write the value of this property suitable for displaying to a user
    // (i.e., this number may be rounded and not an exact representation of
    // the actual value being used). This function calls `toStringForDisplay()`
    // with `precision = 6`.
    std::string toString() const override final {
        return toStringForDisplay(6);
    }

    // Write the value of this property suitable for displaying to a user
    // (i.e., this number may be rounded and not an exact representation of
    // the actual value being used). In general, this means that floats will
    // be represented with the number of significant digits denoted by the
    // `precision` argument, and the default formatting of `stringstream`
    // determines whether or not exponential notation is used.
    std::string toStringForDisplay(const int precision) const override final {
        std::stringstream out;
        if (!this->isOneValueProperty()) out << "(";
        writeSimplePropertyToStreamForDisplay(out, values, precision);
        if (!this->isOneValueProperty()) out << ")";
        return out.str();
    }

    bool isUnnamedProperty() const override final {return false;}
    bool isObjectProperty() const override final {return false;}
    bool isAcceptableObjectTag(const std::string&) const override final 
    {   return false; }

    int getNumValues() const override final {return values.size(); }
    void clearValues() override final {values.clear();}

    bool isEqualTo(const AbstractProperty& other) const override final {
        // Check here rather than in base class because the old
        // Property_Deprecated implementation can't copy this flag right.
        if (this->getValueIsDefault() != other.getValueIsDefault())
            return false;
        assert(this->size() == other.size()); // base class checked
        const SimpleProperty& otherS = SimpleProperty::getAs(other);
        for (int i=0; i<values.size(); ++i)
            if (!Property<T>::TypeHelper::isEqual(values[i], otherS.values[i]))
                return false;
        return true;
    }

    // Property element is a value element, so the values is just a single
    // string. We'll divide into blank-separated tokens and then parse
    // into elements of type T.
    void readFromXMLElement
       (SimTK::Xml::Element& propertyElement,
        int                  versionNumber) override final {
        std::istringstream valstream(propertyElement.getValue());
        if (!readSimplePropertyFromStream(valstream)) {
            std::cerr << "Failed to read " << SimTK::NiceTypeName<T>::name()
            << " property " << this->getName() << "; input='" 
            << valstream.str().substr(0,50) // limit displayed length
            << "'.\n";
        }
        if (values.size() < this->getMinListSize()) {
            std::cerr << "Not enough values for " 
            << SimTK::NiceTypeName<T>::name() << " property " << this->getName() 
            << "; input='" << valstream.str().substr(0,50) // limit displayed length 
            << "'. Expected " << this->getMinListSize()
            << ", got " << values.size() << ".\n";
        }
        if (values.size() > this->getMaxListSize()) {
            std::cerr << "Too many values for " 
            << SimTK::NiceTypeName<T>::name() << " property " << this->getName() 
            << "; input='" << valstream.str().substr(0,50) // limit displayed length 
            << "'. Expected " << this->getMaxListSize()
            << ", got " << values.size() << ". Ignoring extras.\n";

            values.resize(this->getMaxListSize());
        }
    }

    // Property element will be just a value element. We'll serialize it
    // using an unformatted write to produce a series of blank-separated 
    // tokens.
    void writeToXMLElement
       (SimTK::Xml::Element& propertyElement) const override final {
        std::ostringstream valstream;
        writeSimplePropertyToStream(valstream);
        propertyElement.setValue(valstream.str()); 
    } 


    const Object& getValueAsObject(int index=-1) const override final {
        throw OpenSim::Exception(
                "SimpleProperty<T>::getValueAsObject(): property " 
                + this->getName() + " is not an Object property."); 
    }

    Object& updValueAsObject(int index=-1) override final {
        throw OpenSim::Exception(
                "SimpleProperty<T>::updValueAsObject(): property " 
                + this->getName() + " is not an Object property."); 
    }

    void setValueAsObject(const Object& obj, int index=-1) override final {
        throw OpenSim::Exception(
                "SimpleProperty<T>::setValueAsObject(): property " 
                + this->getName() + " is not an Object property."); 
    }

    static bool isA(const AbstractProperty& prop) 
    {   return dynamic_cast<const SimpleProperty*>(&prop) != NULL; }

    static const SimpleProperty& getAs(const AbstractProperty& prop) {
        const SimpleProperty* p = SimTK_DYNAMIC_CAST_DEBUG<const SimpleProperty*>(&prop);
        if (p) return *p;
        throw OpenSim::Exception
           ("SimpleProperty<T>::getAs(): Property " + prop.getName() 
            + " was not of simple type "
            + std::string(SimTK::NiceTypeName<T>::name()),
            __FILE__, __LINE__);
    }

    static SimpleProperty& updAs(AbstractProperty& prop) {
        SimpleProperty* p = SimTK_DYNAMIC_CAST_DEBUG<SimpleProperty*>(&prop);
        if (p) return *p;
        throw OpenSim::Exception
           ("SimpleProperty<T>::updAs(): Property " + prop.getName() 
           + " was not of simple type "
            + std::string(SimTK::NiceTypeName<T>::name()),
            __FILE__, __LINE__);
    }
    int findIndexForName(const SimTK::String& name) const override {
        throw OpenSim::Exception(
            "Property<T>::findIndexForName " + name
            + " called on a list property of non OpenSim Objects. ");
        return -1;
    }
private:
    // This is the Property<T> interface implementation.
    // Base class checks the index.
    const T& getValueVirtual(int index) const   override final 
    {   return values[index]; }
    T& updValueVirtual(int index)               override final 
    {   return values[index]; }
    void setValueVirtual(int index, const T& value) override final
    {   values[index] = value; }
    int appendValueVirtual(const T& value)     override final
    {   values.push_back(value); return values.size()-1; }
    // Adopting a simple property just means we have to delete the one that
    // gets passed in because the caller thinks we took over ownership.
    int adoptAndAppendValueVirtual(T* valuep)     override final
    {   values.push_back(*valuep); // make a copy
        delete valuep; // throw out the old one
        return values.size()-1; }

    // This is the default implementation; specialization is required if
    // the Simbody default behavior is different than OpenSim's; e.g. for
    // Transform serialization.
    bool readSimplePropertyFromStream(std::istream& in) {
        return SimTK::readUnformatted(in, values);
    }

    // This is the default implementation; specialization is required if
    // the Simbody default behavior is different than OpenSim's; e.g. for
    // Transform serialization.
    void writeSimplePropertyToStream(std::ostream& o) const {
        SimTK::writeUnformatted(o, values);
    }

    // This is like an std::vector<T> although with an int index rather
    // than unsigned.
    SimTK::Array_<T,int> values;
};

// We have to provide specializations for Transform because read/write
// unformatted would not know to convert to X-Y-Z body fixed Euler angles
// followed by the position vector.

template <> inline bool SimpleProperty<SimTK::Transform>::
readSimplePropertyFromStream(std::istream& in)
{   
    // Read in an array of Vec6 objects.
    SimTK::Array_<SimTK::Vec6,int> rotTrans;
    values.clear();
    if (!SimTK::readUnformatted(in, rotTrans)) return false;

    // Convert to an array of Transform objects.
    for (int i=0; i<rotTrans.size(); ++i) {
        SimTK::Transform X;
        const SimTK::Vec3& angles = rotTrans[i].getSubVec<3>(0);
        const SimTK::Vec3& pos = rotTrans[i].getSubVec<3>(3);
        X.updR().setRotationToBodyFixedXYZ(angles);
        X.updP() = pos;
        values.push_back(X);
    }
    return true;
}

template <> inline void SimpleProperty<SimTK::Transform>::
writeSimplePropertyToStream(std::ostream& o) const
{   
    // Convert array of Transform objects to an array of Vec6 objects.
    SimTK::Array_<SimTK::Vec6> rotTrans;
    for (int i = 0; i < values.size(); ++i) {
        convertTransformToVec6(rotTrans, values[i]);
    }

    // Now write out the Vec6 objects.
    SimTK::writeUnformatted(o, rotTrans);
}

// We have to provide specializations for string because we want to ignore white space
// if the property allows only one value
template<> inline bool SimpleProperty<std::string>::
readSimplePropertyFromStream(std::istream& in)
{
    if(this->getMaxListSize()==1)
    {
        std::istringstream& instream = (std::istringstream&)(in);
        values.clear();
        values.push_back(instream.str());
        return true;
   }
   else
       return SimTK::readUnformatted(in, values);
}

//==============================================================================
//                             OBJECT PROPERTY
//==============================================================================
/** This subclass of Property<T> is used when type T=O is an "object" type, 
meaning it is derived from %OpenSim's Object serializable base class. **/
template <class T>
class ObjectProperty : public Property<T> {
public:
    /** A one-object property can be unnamed, in which case we use the 
    object type tag as a name for lookup purposes. We consider the property
    unnamed if its name is null or if the object type tag is given explicitly
    as its name. **/
    ObjectProperty(const std::string& name, bool isOneValue) 
    :   isUnnamed(false) {
        objectClassName = T::getClassName();
        if (name.empty() || name == objectClassName) {
            if (!isOneValue) 
                throw OpenSim::Exception(
                    "addProperty<" + objectClassName + 
                    ">(): only a one-object property can be unnamed or use "
                    "the object type as a name.");

            isUnnamed = true;
            this->setName(objectClassName); // use object type as property name
        } else
            this->setName(name);

        if (isOneValue) this->setAllowableListSize(1);
    }

    // Default destructor, copy constructor, copy assignment

    const std::string& getObjectClassName() const {return objectClassName;}


    ObjectProperty* clone() const override final 
    {   return new ObjectProperty(*this); }

    void assign(const AbstractProperty& that) override {
        try {
            *this = dynamic_cast<const ObjectProperty&>(that);
        } catch(const std::bad_cast&) {
            OPENSIM_THROW(InvalidArgument,
                          "Unsupported type. Expected: " + this->getTypeName() +
                          " | Received: " + that.getTypeName());
        }
    }

    // Implementation of these methods must be deferred until Object has been
    // declared; see Object.h.
    std::string toString() const override final;
    bool isAcceptableObjectTag(const std::string& objectTypeTag) const override
        final;
    bool isEqualTo(const AbstractProperty& other) const override final;
    void readFromXMLElement
       (SimTK::Xml::Element& propertyElement,
        int                  versionNumber) override final;
    void writeToXMLElement
       (SimTK::Xml::Element& propertyElement) const override final;
    void setValueAsObject(const Object& obj, int index=-1) override final;

    bool isUnnamedProperty() const override final {return isUnnamed;}
    bool isObjectProperty() const override final {return true;}

    int getNumValues() const override final {return objects.size();}
    void clearValues() override final {objects.clear();}

    const Object& getValueAsObject(int index=-1) const override final {
        if (index < 0 && this->getMinListSize()==1 && this->getMaxListSize()==1)
            index = 0;
        return *objects[index];
    }

    Object& updValueAsObject(int index=-1) override final {
        if (index < 0 && this->getMinListSize()==1 && this->getMaxListSize()==1)
            index = 0;
        return *objects[index];
    }

    static bool isA(const AbstractProperty& prop) 
    {   return dynamic_cast<const ObjectProperty*>(&prop) != NULL; }

    static const ObjectProperty& getAs(const AbstractProperty& prop) {
        const ObjectProperty* p = SimTK_DYNAMIC_CAST_DEBUG<const ObjectProperty*>(&prop);
        if (p) return *p;
        throw OpenSim::Exception
           ("ObjectProperty<T>::getAs(): Property " + prop.getName() 
            + " was not of object type " + T::getClassName());
    }

    static ObjectProperty& updAs(AbstractProperty& prop) {
        ObjectProperty* p = SimTK_DYNAMIC_CAST_DEBUG<ObjectProperty*>(&prop);
        if (p) return *p;
        throw OpenSim::Exception
           ("ObjectProperty<T>::updAs(): Property " + prop.getName() 
           + " was not of object type " + T::getClassName());
    }
    // Return index if name matches, -1 if not found, slow linear search by name
    int findIndexForName(const SimTK::String& name) const override {
        for (int i = 0; i < getNumValues(); ++i)
            if (objects[i]->getName() == name)
                return i;
        return -1;
    }
private:
    // Base class checks the index.
    const T& getValueVirtual(int index) const override final 
    {   return *objects[index]; }
    T& updValueVirtual(int index) override final 
    {   return *objects[index]; }
    void setValueVirtual(int index, const T& obj) override final
    {   objects[index].reset((T*)nullptr);
        objects[index] = obj; }
    int appendValueVirtual(const T& obj) override final
    {   objects.push_back();        // add empty element
        objects.back() = obj;       // insert a copy
        return objects.size()-1; }
    int adoptAndAppendValueVirtual(T* objp) override final
    {   objects.push_back();        // add empty element
        objects.back().reset(objp); // take over ownership
        return objects.size()-1; }

    std::string  objectClassName;
    bool         isUnnamed;    // we'll use the objectTypeTag as a name 

    // This is like an std::vector<ClonePtr<T>>, with an int index rather
    // than unsigned. A ClonePtr is just a pointer that knows to call
    // T::clone() and T::~T() appropriately.
    SimTK::Array_<SimTK::ClonePtr<T>,int> objects;
};
/** @endcond **/ // Hiding SimpleProperty and ObjectProperty

//==============================================================================
//                        TYPE HELPER IMPLEMENTATION
//==============================================================================
// These had to wait for SimpleProperty and ObjectProperty.

template <class T> 
inline ObjectProperty<T>* Property<T>::
TypeHelper::create(const std::string& name, bool isOne) 
{   return new ObjectProperty<T>(name, isOne); }

inline SimpleProperty<bool>* Property<bool>::
TypeHelper::create(const std::string& name, bool isOne) 
{   return new SimpleProperty<bool>(name, isOne); }

inline SimpleProperty<int>* Property<int>::
TypeHelper::create(const std::string& name, bool isOne) 
{   return new SimpleProperty<int>(name, isOne); }

inline SimpleProperty<std::string>* Property<std::string>::
TypeHelper::create(const std::string& name, bool isOne) 
{   return new SimpleProperty<std::string>(name, isOne); }

inline SimpleProperty<double>* Property<double>::
TypeHelper::create(const std::string& name, bool isOne) 
{   return new SimpleProperty<double>(name, isOne); }

inline SimpleProperty<SimTK::Vec3>* Property<SimTK::Vec3>::
TypeHelper::create(const std::string& name, bool isOne) 
{   return new SimpleProperty<SimTK::Vec3>(name, isOne); }

inline SimpleProperty<SimTK::Vec6>* Property<SimTK::Vec6>::
TypeHelper::create(const std::string& name, bool isOne)
{
    return new SimpleProperty<SimTK::Vec6>(name, isOne);
}

inline SimpleProperty<SimTK::Vector>* Property<SimTK::Vector>::
TypeHelper::create(const std::string& name, bool isOne) 
{   return new SimpleProperty<SimTK::Vector>(name, isOne); }

inline SimpleProperty<SimTK::Transform>* Property<SimTK::Transform>::
TypeHelper::create(const std::string& name, bool isOne) 
{   return new SimpleProperty<SimTK::Transform>(name, isOne); }

// Create a self-initializing integer index for fast access to properties
// within an Object's property table.
#ifndef SWIG
SimTK_DEFINE_UNIQUE_INDEX_TYPE(PropertyIndex);
#endif

// Used by OpenSim_DECLARE_PROPERTY_HELPER below to control the members
// that are used with SWIG.
#ifndef SWIG
#define OpenSim_DECLARE_PROPERTY_HELPER_PROPERTY_MEMBERS(name, T)           \
    /** @cond **/                                                           \
    PropertyIndex PropertyIndex_##name;                                     \
    const Property<T>& getProperty_##name() const                           \
    {   return this->template getProperty<T>(PropertyIndex_##name); }       \
    Property<T>& updProperty_##name()                                       \
    {   return this->template updProperty<T>(PropertyIndex_##name); }       \
    /** @endcond **/
#else
// No need to wrap internal PropertyIndex or auto-generated methods that return
// templatized Properties
#define OpenSim_DECLARE_PROPERTY_HELPER_PROPERTY_MEMBERS(name, T)
#endif

// For a property whose effective name (that is, property name or object
// type for unnamed properties) is given, declare a variable to hold
// its PropertyIndex and the methods needed for property access. This is 
// used by all DECLARE_PROPERTY macro variants.
#define OpenSim_DECLARE_PROPERTY_HELPER(name, T)                            \
    OpenSim_DECLARE_PROPERTY_HELPER_PROPERTY_MEMBERS(name, T)               \
    /** @cond **/                                                           \
    void copyProperty_##name(const Self& source)                            \
    {   PropertyIndex_##name = source.PropertyIndex_##name; }               \
    /** @endcond **/                                                        \
    /** Get the value of the i-th element of the <b> name </b> property. */ \
    const T& get_##name(int i) const                                        \
    {   return this->template getProperty<T>(PropertyIndex_##name)[i]; }    \
    /** Get a writable reference to the i-th element of the <b> name </b> property. */ \
    T& upd_##name(int i)                                                    \
    {   return this->template updProperty<T>(PropertyIndex_##name)[i]; }    \
    /** %Set the value of the i-th element of <b> name </b> property.    */ \
    void set_##name(int i, const T& value)                                  \
    {   this->updProperty_##name().setValue(i,value); }                     \
    /** Append an element to the <b> name </b> property.                 */ \
    int append_##name(const T& value)                                       \
    {   return this->updProperty_##name().appendValue(value); }

// All of the list properties share a constructor and set method that take
// a "template template" argument allowing initialization from any container
// of objects of type T that has a size() methods and operator[] indexing.
// And they also include all the methods from the generic helper above.
#define OpenSim_DECLARE_LIST_PROPERTY_HELPER(name, T, comment,              \
                                             minSize, maxSize)              \
    OpenSim_DECLARE_PROPERTY_HELPER(name,T)                                 \
    /** @cond **/                                                           \
    template <template <class> class Container>                             \
    void constructProperty_##name(const Container<T>& initValue)            \
    {   PropertyIndex_##name = this->template addListProperty<T>(#name,     \
            comment, minSize, maxSize, initValue); }                        \
    template <template <class> class Container>                             \
    void set_##name(const Container<T>& value)                              \
    {   this->updProperty_##name().setValue(value); }                       \
    /** @endcond **/


// This is an empty macro that we use to exploit a feature in Doxygen in order
// to nicely document OpenSim properties. See, Doxygen has support for Qt
// "properties", which are slightly similar to our properties. Qt "properties"
// are defined with the Q_PROPERTY() macro. In the code, the macro below is
// empty (as you can tell by...just looking at the macro).  But in the
// Doxyfile, we tell Doxygen that this macro is defined as Q_PROPERTY(). This
// tricks Doxygen into documenting *our* properties as if they were Qt
// properties.  The reason that we don't use Q_PROPERTY() directly is that we
// don't want to prevent our users from potentially using OpenSim in
// conjunction with Qt.  You can see how this empty macro is used in some of
// the macros below.
// We actually also use this macro to document component outputs, etc.
#define OpenSim_DOXYGEN_Q_PROPERTY(T, name)

/** Declare a required, single-value property of the given \a pname and 
type \a T, with an associated \a comment. The value list for this property will
always contain exactly one element, and the property must be initialized at
construction. This macro, and the other similar macros, define several related 
methods. If the property name is my_prop_name, then the defined methods are:
  - constructProperty_my_prop_name(initialValue)
  - getProperty_my_prop_name()
  - updProperty_my_prop_name()
  - get_my_prop_name()
  - upd_my_prop_name()
  - set_my_prop_name(value)

For some property types, the initial value may be omitted during construction.
A data member is also created but is intended for internal use only:
  - PropertyIndex_my_prop_name holds the property table index for this 
    property after it has been constructed

@relates OpenSim::Property **/
#define OpenSim_DECLARE_PROPERTY(pname, T, comment)                         \
    /** @cond **/                                                           \
    OpenSim_DECLARE_PROPERTY_HELPER(pname,T)                                \
    void constructProperty_##pname(const T& initValue) {                    \
        PropertyIndex_##pname =                                             \
            this->template addProperty<T>(#pname,comment,initValue);        \
    }                                                                       \
    /** @endcond **/                                                        \
    /** @name Properties (single-value)                                  */ \
    /** @{                                                               */ \
    /** comment                                                          */ \
    /** This property appears in XML files under                         */ \
    /** the tag <b>\<##pname##\></b>.                                    */ \
    /** This property was generated with                                 */ \
    /** the #OpenSim_DECLARE_PROPERTY macro;                             */ \
    /** see Property to learn about the property system.                 */ \
    /** @see get_##pname##(), upd_##pname##(), set_##pname##()           */ \
    /* This macro below is explained above.                              */ \
    OpenSim_DOXYGEN_Q_PROPERTY(T, pname)                                    \
    /** @}                                                               */ \
    /** @name Property-related functions                                 */ \
    /** @{                                                               */ \
    /** Get the value of the <b> pname </b> property.                    */ \
    const T& get_##pname() const                                            \
    {   return this->getProperty_##pname().getValue(); }                    \
    /** Get a writable reference to the <b> pname </b> property.        */ \
    T& upd_##pname()                                                        \
    {   return this->updProperty_##pname().updValue(); }                    \
    /** %Set the value of the <b> pname </b> property.                   */ \
    void set_##pname(const T& value)                                        \
    {   this->updProperty_##pname().setValue(value); }                      \
    /** @}                                                               */


/** Declare a required, unnamed property holding exactly one object of type
T derived from %OpenSim's Object class and identified by that object's class 
name rather than a property name. At construction, this property must be 
initialized with an object of type T.
@relates OpenSim::Property **/
#define OpenSim_DECLARE_UNNAMED_PROPERTY(T, comment)                        \
    /** @cond **/                                                           \
    OpenSim_DECLARE_PROPERTY_HELPER(T,T)                                    \
    void constructProperty_##T(const T& initValue)                          \
    {   PropertyIndex_##T =                                                 \
            this->template addProperty<T>("", comment, initValue); }        \
    /** @endcond **/                                                        \
    /** @name Properties (unnamed)                                       */ \
    /** @{                                                               */ \
    /** comment                                                          */ \
    /** This property appears in XML files under                         */ \
    /** the tag <b>\<%##T##\></b>.                                       */ \
    /** This property was generated with the                             */ \
    /** #OpenSim_DECLARE_UNNAMED_PROPERTY macro;                         */ \
    /** see Property to learn about the property system.                 */ \
    /** @see get_##T##(), upd_##T##(), set_##T##()                       */ \
    /* This macro below is explained above.                              */ \
    OpenSim_DOXYGEN_Q_PROPERTY(T, T)                                        \
    /** @}                                                               */ \
    /** @name Property-related functions                                 */ \
    /** @{                                                               */ \
    /** Get the value of the <b> %##T </b> property.                     */ \
    const T& get_##T() const                                                \
    {   return this->getProperty_##T().getValue(); }                        \
    /** Get a writable reference to the <b> %##T </b> property.          */ \
    T& upd_##T()                                                            \
    {   return this->updProperty_##T().updValue(); }                        \
    /** %Set the value of the <b> %##T </b> property.                    */ \
    void set_##T(const T& value)                                            \
    {   this->updProperty_##T().setValue(value); }                          \
    /** @}                                                               */


/** Declare a property of the given \a pname containing an optional value of
the given type T (that is, the value list can be of length 0 or 1 only).
The property may be constructed as empty, or with initialization to a single
value of type T.
@relates OpenSim::Property **/
#define OpenSim_DECLARE_OPTIONAL_PROPERTY(pname, T, comment)                \
    /** @cond **/                                                           \
    OpenSim_DECLARE_PROPERTY_HELPER(pname,T)                                \
    void constructProperty_##pname()                                        \
    {   PropertyIndex_##pname =                                             \
            this->template addOptionalProperty<T>(#pname, comment); }       \
    void constructProperty_##pname(const T& initValue)                      \
    {   PropertyIndex_##pname =                                             \
            this->template addOptionalProperty<T>(#pname, comment,          \
                                                  initValue); }             \
    /** @endcond **/                                                        \
    /** @name Properties (optional)                                      */ \
    /** @{                                                               */ \
    /** comment                                                          */ \
    /** This property appears in XML files under                         */ \
    /** the tag <b>\<##pname##\></b>.                                    */ \
    /** This property was generated with                                 */ \
    /** the #OpenSim_DECLARE_OPTIONAL_PROPERTY macro;                    */ \
    /** see Property to learn about the property system.                 */ \
    /** @see get_##pname##(), upd_##pname##(), set_##pname##()           */ \
    /* This macro below is explained above.                              */ \
    OpenSim_DOXYGEN_Q_PROPERTY(T, pname)                                    \
    /** @}                                                               */ \
    /** @name Property-related functions                                 */ \
    /** @{                                                               */ \
    /** Get the value of the <b> pname </b> property.                    */ \
    const T& get_##pname() const                                            \
    {   return this->getProperty_##pname().getValue(); }                    \
    /** Get a writable reference to the <b> pname </b> property.         */ \
    T& upd_##pname()                                                        \
    {   return this->updProperty_##pname().updValue(); }                    \
    /** %Set the value of the <b> pname </b> property.                   */ \
    void set_##pname(const T& value)                                        \
    {   this->updProperty_##pname().setValue(value); }                      \
    /** @}                                                               */


/** Declare a property of the given \a pname containing a variable-length
list of values of the given type T. The property may be constructed as empty, 
or with initialization to a templatized Container\<T> for any Container that
supports a %size() method and operator[] element selection.
@see OpenSim_DECLARE_LIST_PROPERTY_SIZE()
@see OpenSim_DECLARE_LIST_PROPERTY_ATLEAST()
@see OpenSim_DECLARE_LIST_PROPERTY_ATMOST()
@see OpenSim_DECLARE_LIST_PROPERTY_RANGE()
@relates OpenSim::Property **/
#define OpenSim_DECLARE_LIST_PROPERTY(pname, T, comment)                    \
    /** @name Properties (list)                                          */ \
    /** @{                                                               */ \
    /** comment                                                          */ \
    /** This property appears in XML files under                         */ \
    /** the tag <b>\<##pname##\></b>.                                    */ \
    /** This property holds a \a list of objects, and was generated with */ \
    /** the #OpenSim_DECLARE_LIST_PROPERTY macro;                        */ \
    /** see Property to learn about the property system.                 */ \
    /** @see get_##pname##(), upd_##pname##(), set_##pname##(),          */ \
    /**     append_##pname##()                                           */ \
    /* This macro below is explained above.                              */ \
    OpenSim_DOXYGEN_Q_PROPERTY(T, pname)                                    \
    /** @}                                                               */ \
    /** @name Property-related functions                                 */ \
    /** @{                                                               */ \
    OpenSim_DECLARE_LIST_PROPERTY_HELPER(pname, T, comment,                 \
                                         0, std::numeric_limits<int>::max())\
    /** @cond **/                                                           \
    void constructProperty_##pname()                                        \
    {   PropertyIndex_##pname = this->template addListProperty<T>           \
           (#pname, comment, 0, std::numeric_limits<int>::max()); }         \
    /** @endcond **/                                                        \
    /** @}                                                               */

/** Declare a property of the given \a pname containing a list of values of 
the given type T, with the number of values in the list restricted to be
exactly \a listSize (> 0) elements, no more or less. A fixed-size property must 
be initialized at construction, by providing a templatized Container\<T> with
the right number of elements, using any Container that supports a %size() 
method and operator[] element selection.
@relates OpenSim::Property **/
#define OpenSim_DECLARE_LIST_PROPERTY_SIZE(pname, T, listSize, comment)     \
    /** @name Properties (list)                                          */ \
    /** @{                                                               */ \
    /** comment                                                          */ \
    /** This property appears in XML files under                         */ \
    /** the tag <b>\<##pname##\></b>.                                    */ \
    /** This property holds a \a list of exactly listSize object(s),     */ \
    /** and was generated with                                           */ \
    /** the #OpenSim_DECLARE_LIST_PROPERTY_SIZE macro;                   */ \
    /** see Property to learn about the property system.                 */ \
    /** @see get_##pname##(), upd_##pname##(), set_##pname##()           */ \
    /* This macro below is explained above.                              */ \
    OpenSim_DOXYGEN_Q_PROPERTY(T, pname)                                    \
    /** @}                                                               */ \
    /** @name Property-related functions                                 */ \
    /** @{                                                               */ \
    OpenSim_DECLARE_LIST_PROPERTY_HELPER(pname, T, comment,                 \
                                         (listSize), (listSize))            \
    /** @}                                                               */

/** Declare a property of the given \a pname containing a list of values of 
the given type T, with the number of values required to be at least 
\a minSize (> 0) elements. Such a property must be initialized at construction, 
by providing a templatized Container\<T> with at least \a minSize elements, 
using any Container that supports a %size() method and operator[] element 
selection.
@relates OpenSim::Property **/
#define OpenSim_DECLARE_LIST_PROPERTY_ATLEAST(pname, T, minSize, comment)   \
    /** @name Properties (list)                                          */ \
    /** @{                                                               */ \
    /** comment                                                          */ \
    /** This property appears in XML files under                         */ \
    /** the tag <b>\<##pname##\></b>.                                    */ \
    /** This property holds a \a list of minSize or more objects,        */ \
    /** and was generated with                                           */ \
    /** the #OpenSim_DECLARE_LIST_PROPERTY_ATLEAST macro;                */ \
    /** see Property to learn about the property system.                 */ \
    /** @see get_##pname##(), upd_##pname##(), set_##pname##(),          */ \
    /**     append_##pname##()                                           */ \
    /* This macro below is explained above.                              */ \
    OpenSim_DOXYGEN_Q_PROPERTY(T, pname)                                    \
    /** @}                                                               */ \
    /** @name Property-related functions                                 */ \
    /** @{                                                               */ \
    OpenSim_DECLARE_LIST_PROPERTY_HELPER(pname, T, comment,                 \
                                (minSize), std::numeric_limits<int>::max()) \
    /** @}                                                               */

/** Declare a property of the given \a pname containing a list of values of 
the given type T, with the number of values in the list restricted to be
no more than \a maxSize (> 0) elements.  This kind of property may optionally 
be initialized at construction, by providing a templatized Container\<T> with 
no more than \a maxSize elements, using any Container that supports a %size() 
method and operator[] element selection.
@relates OpenSim::Property **/
#define OpenSim_DECLARE_LIST_PROPERTY_ATMOST(pname, T, maxSize, comment)    \
    /** @name Properties (list)                                          */ \
    /** @{                                                               */ \
    /** comment                                                          */ \
    /** This property appears in XML files under                         */ \
    /** the tag <b>\<##pname##\></b>.                                    */ \
    /** This property holds a \a list of at most maxSize object(s),      */ \
    /** and was generated with                                           */ \
    /** the #OpenSim_DECLARE_LIST_PROPERTY_ATMOST macro;                 */ \
    /** see Property to learn about the property system.                 */ \
    /** @see get_##pname##(), upd_##pname##(), set_##pname##(),          */ \
    /**     append_##pname##()                                           */ \
    /* This macro below is explained above.                              */ \
    OpenSim_DOXYGEN_Q_PROPERTY(T, pname)                                    \
    /** @}                                                               */ \
    /** @name Property-related functions                                 */ \
    /** @{                                                               */ \
    OpenSim_DECLARE_LIST_PROPERTY_HELPER(pname, T, comment, 0, (maxSize))   \
    /** @cond **/                                                           \
    void constructProperty_##pname()                                        \
    {   PropertyIndex_##pname = addListProperty<T>(#pname, comment,         \
                                                  0, (maxSize)); }          \
    /** @endcond **/                                                        \
    /** @}                                                               */

/** Declare a property of the given \a pname containing a list of values of 
the given type T, with the number of values in the list restricted to be
in the range \a minSize (> 0) to \a maxSize (> \a minSize).  This kind of 
property must be initialized with at least \a minSize values at construction. 
If you want to allow zero elements, so that initialization is optional, use 
OpenSim_DECLARE_PROPERTY_ATMOST() rather than this macro.
@relates OpenSim::Property **/
#define OpenSim_DECLARE_LIST_PROPERTY_RANGE(pname, T, minSize, maxSize,     \
                                            comment)                        \
    /** @name Properties (list)                                          */ \
    /** @{                                                               */ \
    /** comment                                                          */ \
    /** This property appears in XML files under                         */ \
    /** the tag <b>\<##pname##\></b>.                                    */ \
    /** This property holds a \a list of between minSize and maxSize     */ \
    /** objects,                                                         */ \
    /** and was generated with                                           */ \
    /** the #OpenSim_DECLARE_LIST_PROPERTY_RANGE macro;                  */ \
    /** see Property to learn about the property system.                 */ \
    /** @see get_##pname##(), upd_##pname##(), set_##pname##(),          */ \
    /**     append_##pname##()                                           */ \
    /* This macro below is explained above.                              */ \
    OpenSim_DOXYGEN_Q_PROPERTY(T, pname)                                    \
    /** @}                                                               */ \
    /** @name Property-related functions                                 */ \
    /** @{                                                               */ \
    OpenSim_DECLARE_LIST_PROPERTY_HELPER(pname, T, comment,                 \
                                        (minSize), (maxSize))               \
    /** @}                                                               */

} //namespace
//=============================================================================
//=============================================================================

#endif // OPENSIM_PROPERTY_H_
